
local alien   = require 'alien'
local gl      = require 'bindings.gl'
local imageio = require 'imageio'
local require, assert, tonumber, print, pairs, error, type
    = require, assert, tonumber, print, pairs, error, type
local strchar
    = string.char
local floor, random
    = math.floor, math.random
local tconcat
    = table.concat

module (...)


local width, height

function dimensions(new_width, new_height)
  if new_width then
    width, height = assert(tonumber(new_width), "width must be a number"), assert(tonumber(new_height), "height must be a number")
  else
    return width, height
  end
end

local window
local windowWidth, windowHeight

function declareWindowSize(w,h)
  local x, y = floor((w-width)/2), floor((h-height)/2)
  local scaleX, scaleY = 1, 1
  local maxX, maxY = width, height
  window.declareMouseOffset(-x, -y)
  window.declareMouseScale(scaleX, scaleY)
  window.declareMouseMax(maxX, maxY)
  gl.Viewport(x, y, width, height)
end

function init()
  window = require 'guac.window'
  assert(window.init_opengl, "window mode does not support opengl")()
end

local back_r, back_g, back_b = 0, 0, 0

function backgroundColor(new_r, new_g, new_b)
  if new_r then
    back_r, back_g, back_b = new_r, new_g, new_b
  else
    return back_r, back_g, back_b
  end
end

local function _onrender() end
function declareRenderFunc(func)
  _onrender = func
end

function internal_render()
  
  gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
  gl.Enable(gl.BLEND)
  gl.Enable(gl.TEXTURE_2D)
  gl.ShadeModel(gl.SMOOTH)
  gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
  gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
  gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
  
  gl.MatrixMode(gl.PROJECTION)
  gl.LoadIdentity()
  gl.Ortho(0, width, height, 0, 0, 1)
  gl.MatrixMode(gl.MODELVIEW)
  
  -- draw in here
  gl.Clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT)
  
  gl.BindTexture(gl.TEXTURE_2D, 0)
  
  gl.Color3f(back_r, back_g, back_b)
  gl.Begin(gl.QUADS)
    gl.Vertex3f(0, 0, 0)
    gl.Vertex3f(width, 0, 0)
    gl.Vertex3f(width, height, 0)
    gl.Vertex3f(0, height, 0)
  gl.End()
  
  _onrender()
  
end

local texbuf = alien.buffer(alien.sizeof('uint'))
texbuf:set(1, 0, 'uint')
function loadImage(path_or_pixmap)
  if (type(path_or_pixmap) == 'string') then
    local path = path_or_pixmap
    local reader = assert(imageio.readfile(path))
    gl.GenTextures(1, texbuf)
    local texture = texbuf:get(1, 'uint')
    gl.BindTexture(gl.TEXTURE_2D, texture)
    gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
    gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
    gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
    gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
    gl.TexImage2D(gl.TEXTURE_2D, 0, 4, reader.width, reader.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, nil)
    while true do
      local start_row, row_count, data = reader:getdata()
      if (start_row == nil) then
        break
      end
      gl.TexSubImage2D(gl.TEXTURE_2D, 0, 0, start_row-1, reader.width, row_count, gl.RGBA, gl.UNSIGNED_BYTE, data)
    end
    return {width=reader.width, height=reader.height, texture=texture}
  else
    local pixmap = path_or_pixmap
    gl.GenTextures(1, texbuf)
    local texture = texbuf:get(1, 'uint')
    gl.BindTexture(gl.TEXTURE_2D, texture)
    gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
    gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
    gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
    gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
    gl.TexImage2D(gl.TEXTURE_2D, 0, 4, pixmap.width, pixmap.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixmap.buffer)
    return {width=pixmap.width, height=pixmap.height, texture=texture}
  end
end

function drawImage(img, x, y, xflip, yflip)

  local xratio, yratio = img.xratio or 1, img.yratio or 1
  local width, height = img.width, img.height
	
  gl.Color3f(1, 1, 1)
  gl.BindTexture(gl.TEXTURE_2D, img.texture)
  gl.Begin(gl.QUADS)
    gl.TexCoord2f(xflip and xratio or 0, yflip and yratio or 0) ; gl.Vertex2f(x,        y)
    gl.TexCoord2f(xflip and 0 or xratio, yflip and yratio or 0) ; gl.Vertex2f(x+width,  y)
    gl.TexCoord2f(xflip and 0 or xratio, yflip and 0 or yratio) ; gl.Vertex2f(x+width,  y+height)
    gl.TexCoord2f(xflip and xratio or 0, yflip and 0 or yratio) ; gl.Vertex2f(x,        y+height)
  gl.End()
  
end
